/*
 * Copyright (C) 2010 TopCoder Inc., All Rights Reserved.
 */
package com.hercules.android.receiver.commands;

import java.util.Map;

import org.json.JSONException;
import org.json.JSONObject;

import android.os.Handler;
import android.util.Log;

import com.hercules.android.receiver.Config;
import com.hercules.android.receiver.Receiver;
import com.hercules.android.receiver.ReceiverUtil;

/**
 * <p>
 * This command handler class will aggregate all the command types and their handler object. When a command need to be
 * processed, it will call the corresponding handler to handle the command message.
 * </p>
 * 
 * @author TCSASSEMBER
 * @version 1.0
 */
public class AggregateXRECommandHandler extends XRECommandHandler {
    /**
     * Represents the mapping from command type to the corresponding <code>XRECommandHandler</code> instance.
     */
    private Map<String, XRECommandHandler> commandHandlers;

    /**
     * Create a new <code>AggregateXRECommandHandler</code> with the <code>Receiver</code> and the mapping from command
     * type to the corresponding <code>XRECommandHandler</code> instance.
     * 
     * @param receiver
     *            the <code>Receiver</code> instance.
     * @param commandHandlers
     *            the mapping from command type to the corresponding <code>XRECommandHandler</code> instance.
     * @throws IllegalArgumentException
     *             if arguments is null
     */
    public AggregateXRECommandHandler(Receiver receiver, Map<String, XRECommandHandler> commandHandlers) {
        super(receiver);

        ReceiverUtil.checkNull("commandHandlers", commandHandlers);

        this.commandHandlers = commandHandlers;
    }

    /**
     * Log message before processing the command message.
     * 
     * @param message
     *            the command message to be processed.
     * @throws XRECommandHandlerException
     *             if any error occurs
     */
    protected void preProcessCommand(JSONObject message) throws XRECommandHandlerException {
        Log.v(Config.APPLICATION_NAME, "Pre process command:" + message.toString());
    }

    /**
     * Log message after processing the command message.
     * 
     * @param message
     *            the command message to be processed.
     * @throws XRECommandHandlerException
     *             if any error occurs
     */
    protected void postProcessCommand(JSONObject message) throws XRECommandHandlerException {
        Log.v(Config.APPLICATION_NAME, "Post process command:" + message.toString());
    }

    /**
     * Process the command message. It will call the corresponding handler to handle the command message.
     * 
     * @param message
     *            the command message to be processed.
     * @throws XRECommandHandlerException
     *             if any other error occurs
     */
    public void processCommand(JSONObject message) throws XRECommandHandlerException {
        try {
            receiver.getApplicationData().setCurrentCommandIndex(message.getInt("commandIndex") + 1);

            String commandType = message.getString("command");
            XRECommandHandler handler = commandHandlers.get(commandType);
            if (handler == null) {
                throw new XRECommandHandlerException("The command [" + commandType + "] can't be recognized.");
            }
            handler.onCommandMessage(message);

            if (handler.needRedraw(message)) {
                // update root view
                Handler mHandler = receiver.getApplicationData().getRootViewUpdateHandler();
                mHandler.sendMessage(mHandler.obtainMessage());
            }
        } catch (JSONException e) {
            throw new XRECommandHandlerException("Error occurs when reading from json.", e);
        }
    }
}
